﻿//-----------------------------------------------------------------------
// <Copyright>
// * Copyright (C) 2022 RuYiAdmin All Rights Reserved
// </Copyright>
//-----------------------------------------------------------------------

using Microsoft.AspNetCore.Http;
using RuYiAdmin.Net.CommonInfrastructure.Configurations;
using RuYiAdmin.Net.CommonInfrastructure.Enums.Framework;
using RuYiAdmin.Net.CommonInfrastructure.Models;
using RuYiAdmin.Net.EntityDataModel.DataTransformationModel.SystemModel;
using RuYiAdmin.Net.EntityDataModel.EntityModel.SystemModel;
using RuYiAdmin.Net.EntityDataModel.SessionScope;
using RuYiAdmin.Net.RepositoryLayer.DataRepository.Interface.FrameworkInterface;
using RuYiAdmin.Net.RepositoryLayer.DataRepository.Interface.SystemInterface;
using RuYiAdmin.Net.ServiceLayer.BaseService.Implementation;
using RuYiAdmin.Net.ServiceLayer.BusinessService.Interface.SystemInterface;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;

namespace RuYiAdmin.Net.ServiceLayer.BusinessService.Implementation.SystemImplementation
{
    /// <summary>
    /// 机构业务层实现
    /// </summary>
    public class SysOrganizationService : RuYiAdminBaseService<SysOrganization>, ISysOrganizationService
    {
        #region 属性及构造函数

        /// <summary>
        ///机构仓储实例
        /// </summary>
        private readonly ISysOrganizationRepository OrganizationRepository;

        /// <summary>
        /// HttpContext
        /// </summary>
        private readonly IHttpContextAccessor ContextAccessor;

        /// <summary>
        /// Redis仓储实例
        /// </summary>
        private readonly IRedisRepository RedisRepository;

        /// <summary>
        /// 业务日志仓储接口实例
        /// </summary>
        private readonly ILoggerRepository LoggerRepository;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="OrganizationRepository"></param>
        /// <param name="ContextAccessor"></param>
        /// <param name="RedisRepository"></param>
        /// <param name="LoggerRepository"></param>
        public SysOrganizationService(ISysOrganizationRepository OrganizationRepository,
                                      IHttpContextAccessor ContextAccessor,
                                      IRedisRepository RedisRepository,
                                      ILoggerRepository LoggerRepository) : base(OrganizationRepository)
        {
            this.OrganizationRepository = OrganizationRepository;
            this.ContextAccessor = ContextAccessor;
            this.RedisRepository = RedisRepository;
            this.LoggerRepository = LoggerRepository;
        }

        #endregion

        #region 业务层公有方法

        #region 获取机构树

        /// <summary>
        /// 获取机构树
        /// </summary>
        /// <returns>ActionResponseResult</returns>
        public async Task<QueryResponseResult<SysOrganizationDTO>> GetOrgTreeNodes()
        {
            var orgs = await this.RedisRepository.GetAsync<List<SysOrganizationDTO>>(RuYiGlobalConfig.SystemCacheConfig.OrgCacheName);

            //获取用户机构编号
            var orgId = RuYiSessionContext.GetUserOrgId(this.ContextAccessor);
            var root = orgs.Where(t => t.Id == orgId).FirstOrDefault();

            GetNodeChildren(root, orgs);

            var queryResponseResult = new QueryResponseResult<SysOrganizationDTO>();
            queryResponseResult.HttpStatusCode = HttpStatusCode.OK;
            queryResponseResult.Message = new string("OK");
            queryResponseResult.List = new List<SysOrganizationDTO>();
            queryResponseResult.List.Add(root);

            return queryResponseResult;
        }

        #endregion

        #region 获取机构、用户树

        /// <summary>
        /// 获取机构、用户树
        /// </summary>
        /// <returns></returns>
        public async Task<QueryResponseResult<OrgUserTreeDTO>> GetOrgUserTree()
        {
            return await Task.Run(() =>
            {
                var sqlKey = "sqls:sql:query_org_user_tree_org";
                var strSQL = this.GetSqlByKey(sqlKey);

                //获取用户机构编号
                var orgId = RuYiSessionContext.GetUserOrgId(this.ContextAccessor);
                strSQL = string.Format(strSQL, orgId);

                int totalCount = 0;
                var root = this.OrganizationRepository.
                    SqlQuery<OrgUserTreeDTO>(new SearchCondition(), ref totalCount, strSQL).
                    FirstOrDefault();

                InitOrgUserTreeChildren(root, sqlKey);

                var queryResponseResult = new QueryResponseResult<OrgUserTreeDTO>();
                queryResponseResult.HttpStatusCode = HttpStatusCode.OK;
                queryResponseResult.Message = new string("OK");
                queryResponseResult.List = new List<OrgUserTreeDTO>();
                queryResponseResult.List.Add(root);

                return queryResponseResult;
            });
        }

        #endregion

        #region 加载系统机构缓存

        /// <summary>
        /// 加载系统机构缓存
        /// </summary>
        public async Task LoadSystemOrgCache()
        {
            var strSQL = this.GetSqlByKey("sqls:sql:query_org_info");

            int totalCount = 0;
            var orgs = await this.OrganizationRepository.SqlQueryAsync<SysOrganizationDTO>(new SearchCondition(), totalCount, strSQL);
            await this.RedisRepository.SetAsync(RuYiGlobalConfig.SystemCacheConfig.OrgCacheName, orgs, -1);

            this.LoggerRepository.Info("系统机构缓存加载完成");
        }

        #endregion

        #region 清理系统机构缓存

        /// <summary>
        /// 清理系统机构缓存
        /// </summary>
        public async Task ClearSystemOrgCache()
        {
            await this.RedisRepository.DeleteAsync(new string[] { RuYiGlobalConfig.SystemCacheConfig.OrgCacheName });

            this.LoggerRepository.Info("系统机构缓存清理完成");
        }

        #endregion

        #endregion

        #region 业务层私有方法

        #region 递归机构树

        /// <summary>
        /// 递归机构树
        /// </summary>
        /// <param name="root">根节点</param>
        /// <param name="orgs">机构列表</param>
        private void GetNodeChildren(SysOrganizationDTO root, List<SysOrganizationDTO> orgs)
        {
            var list = orgs.Where(t => t.ParentId == root.Id).ToList();

            if (list.Count > 0)
            {
                root.Children = new List<SysOrganizationDTO>();
                root.Children.AddRange(list.OrderBy(t => t.SerialNumber).ToList());

                foreach (var item in list)
                {
                    GetNodeChildren(item, orgs);
                }
            }
        }

        #endregion

        #region 递归机构、用户树

        /// <summary>
        /// 递归机构、用户树
        /// </summary>
        /// <param name="root"></param>
        /// <param name="sqlKey"></param>
        private void InitOrgUserTreeChildren(OrgUserTreeDTO root, string sqlKey)
        {
            #region 初始化节点下用户

            string strSQL = this.GetSqlByKey("sqls:sql:query_org_user_tree_user");

            strSQL = string.Format(strSQL, root.Id);
            int totalCount = 0;
            var users = this.OrganizationRepository.SqlQuery<OrgUserTreeDTO>(new SearchCondition(), ref totalCount, strSQL);

            if (users.Count > 0)
            {
                root.Children = new List<OrgUserTreeDTO>();
                root.Children.AddRange(users.OrderBy(t => t.SerialNumber).ToList());
            }

            #endregion

            #region 初始化节点下机构

            var searchCondition = new SearchCondition();
            searchCondition.SearchItems = new List<SearchItem>();
            searchCondition.SearchItems.Add(new SearchItem()
            {
                Field = "PARENT_ID",
                DataType = DataType.Guid,
                SearchMethod = SearchMethod.Equal,
                Value = root.Id
            });

            strSQL = this.GetSqlByKey(sqlKey).Replace("AND o.ID = '{0}'", "");

            totalCount = 0;
            var orgs = this.OrganizationRepository.SqlQuery<OrgUserTreeDTO>(searchCondition, ref totalCount, strSQL);

            if (orgs.Count > 0)
            {
                if (root.Children == null)
                {
                    root.Children = new List<OrgUserTreeDTO>();
                }
                root.Children.AddRange(orgs.OrderBy(t => t.SerialNumber).ToList());
            }

            #endregion

            #region 递归初始化子集

            foreach (var item in orgs)
            {
                InitOrgUserTreeChildren(item, sqlKey);
            }

            #endregion
        }

        #endregion

        #endregion
    }
}
